package com.wenzheng.quartz.common.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 获取Spring容器中bean工具类
 * @author
 * @date   2018年6月6日
 * 
 */
@Component("springContextUtils")
public class SpringContextUtils implements ApplicationContextAware {

	private static ApplicationContext applicationContext = null;

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	@SuppressWarnings("unchecked")
	public static <T> T getBean(String beanId) {
		return (T) applicationContext.getBean(beanId);
	}

	public static <T> T getBean(Class<T> requiredType) {
		return (T) applicationContext.getBean(requiredType);
	}

	/**
	 * 获取Spring容器中指定接口的所有实例（支持Order注解）
	 * @param requiredType
	 * @return
	 */
	public static <T> List<T> getBeansWithSort(Class<T> requiredType) {
		List<T> list = new ArrayList<>();
		TreeSet<T> set = new TreeSet<>((x,y) -> {
			Integer xOrderValue = null;
			Integer yOrderValue = null;
			String xName = x.getClass().getSimpleName();
			String yName = y.getClass().getSimpleName();
			// 获取注解的值
			Order xAnnotation = x.getClass().getAnnotation(org.springframework.core.annotation.Order.class);
			Order yAnnotation = y.getClass().getAnnotation(org.springframework.core.annotation.Order.class);
			if(null != xAnnotation) {
				xOrderValue = xAnnotation.value();
			}
			if(null != yAnnotation) {
				yOrderValue = yAnnotation.value();
			}
			// 确定返回值
			if (xOrderValue == null && yOrderValue == null) {
				// 都没有注解时，用名字来比较
				return xName.compareTo(yName);
			} else if (xOrderValue != null && yOrderValue != null) {
				// 都有注解，则内容小的排在前面
				return xOrderValue.compareTo(yOrderValue);
			} else {
				// 一个有注解，一个没有注解时，有注解的排的在前面，没有注解的排在后面. 根据红黑树，返回正数则放在右边，返回负数则放在左边
				return xOrderValue == null ? 1 : -1;
			}
		});
		Map<String, T> map = applicationContext.getBeansOfType(requiredType);
		if(map == null || map.size() < 1) {
			throw new RuntimeException("get bean exception with" + requiredType.getName());
		}
		Set<Entry<String,T>> entrySet = map.entrySet();
		for (Entry<String, T> entry : entrySet) {
			set.add(entry.getValue());
		}
		list.addAll(set);
		return list;
	}
	
	
	/**
	 * Spring容器启动后，会把 applicationContext 给自动注入进来，然后我们把 applicationContext 赋值到静态变量中，方便后续拿到容器对象
	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		SpringContextUtils.applicationContext = applicationContext;
	}


}
